Raw code available at SW_Morphology

Study Design

Setup

Load all packages

# libraries
library(car)
library(coxme)
library(dplyr)
library(ehahelper)
library(ggeffects)
library(ggplot2)
library(ggpubr)
library(ggthemes)
library(lme4)
library(lmerTest)
library(readr)
library(sjmisc)
library(survival)

sessionInfo()

sessionInfo()
R version 4.3.0 (2023-04-21)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.4

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/London
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] sjmisc_2.8.9       readr_2.1.4        ggthemes_4.2.4     ggpubr_0.6.0      
 [5] ggplot2_3.4.2      ggeffects_1.2.2    ehahelper_0.3.9999 dplyr_1.1.2       
 [9] coxme_2.2-18.1     survival_3.5-5     car_3.1-2          carData_3.0-5     
[13] bdsmatrix_1.3-6    lmerTest_3.1-3     lme4_1.1-33        Matrix_1.5-4      

loaded via a namespace (and not attached):
 [1] utf8_1.2.3          generics_0.1.3      tidyr_1.3.0         rstatix_0.7.2      
 [5] stringi_1.7.12      lattice_0.21-8      hms_1.1.3           magrittr_2.0.3     
 [9] grid_4.3.0          backports_1.4.1     gridExtra_2.3       purrr_1.0.1        
[13] fansi_1.0.4         scales_1.2.1        eha_2.10.3          numDeriv_2016.8-1.1
[17] abind_1.4-5         cli_3.6.1           rlang_1.1.1         cowplot_1.1.1      
[21] munsell_0.5.0       splines_4.3.0       withr_2.5.0         tools_4.3.0        
[25] tzdb_0.3.0          nloptr_2.0.3        ggsignif_0.6.4      minqa_1.2.5        
[29] colorspace_2.1-0    sjlabelled_1.2.0    boot_1.3-28.1       broom_1.0.4        
[33] vctrs_0.6.2         R6_2.5.1            lifecycle_1.0.3     stringr_1.5.0      
[37] MASS_7.3-60         insight_0.19.1      pkgconfig_2.0.3     pillar_1.9.0       
[41] gtable_0.3.3        glue_1.6.2          Rcpp_1.0.10         xfun_0.39          
[45] tibble_3.2.1        tidyselect_1.2.0    rstudioapi_0.14     knitr_1.42         
[49] nlme_3.1-162        compiler_4.3.0     

Data files

Data file ADD_I is available on the github page.

Morphometric and Island Comparison

Preparing Data

# read the data file "ADD_I"
ADD_I <- read_csv("Tables/ADD_I.csv", col_types = cols(Island = col_factor(levels = c("CN","AR", "CE", "DS", "FR"))))
# create the earliest born individuals on each island
Isfy <- ADD_I %>% select(founderyear,Island) %>% filter(!duplicated(Island))
# create a data frame with means and sd of each morphometric
ADD_mean <- ADD_I %>% group_by(Island,BirthYear) %>% summarise(RTsd = sd(RightTarsus,na.rm=TRUE),WLsd = sd(WingLength,na.rm=TRUE),BMsd = sd(BodyMass,na.rm=TRUE),HBsd=sd(HeadBill,na.rm=TRUE),RightTarsus=mean(RightTarsus,na.rm=TRUE),WingLength=mean(WingLength,na.rm=TRUE),BodyMass=mean(BodyMass,na.rm=TRUE),HeadBill=mean(HeadBill,na.rm=TRUE))

Linear Mixed Effect Models

Tarsus Length

####RightTarsus ----
IRTlmer <- lmer(RightTarsus ~  Island*fYear + Sex + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IRTlmer)

#predicting the model 
IRTlmerdata <- ggpredict(IRTlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,RightTarsus=predicted,Island=group,Sex=facet)
IRTlmerdata2 <- merge(IRTlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 25)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11))%>% mutate(BirthYear = fYear + founderyear) %>% group_by(Island,BirthYear) %>% summarise(RightTarsus = mean(RightTarsus, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model (shown as ggarrange below)
IRTmod <- ggplot(IRTlmerdata2, aes(x = BirthYear, y = RightTarsus, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=RightTarsus,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=RightTarsus-RTsd,ymax=RightTarsus+RTsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "loess", se = FALSE) + 
  geom_ribbon(aes(ymin=RightTarsus-std.error,ymax=RightTarsus+std.error),alpha=0.5) +
  labs(x = "Birth Year", y= "Tarsus Length (mm)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Body Mass

#### Body Mass ----
IBMlmer <- lmer(BodyMass ~  Island*fYear + Sex  + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IBMlmer)

#predicting the model
IBMlmerdata <- ggpredict(IBMlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,BodyMass=predicted,Island=group,Sex=facet)
IBMlmerdata2 <- merge(IBMlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 25)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11))%>% mutate(BirthYear = fYear + founderyear)  %>% group_by(Island,BirthYear) %>% summarise(BodyMass = mean(BodyMass, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model
IBMmod <- ggplot(IBMlmerdata2, aes(x = BirthYear, y = BodyMass, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=BodyMass,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=BodyMass-BMsd,ymax=BodyMass+BMsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "lm", se = FALSE) + 
  geom_ribbon(aes(ymin=BodyMass-std.error,ymax=BodyMass+std.error),alpha=0.5) +
  labs(x = "Birth Year", y= "Body Mass (g)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Wing Length

#### Wing Length ----
IWLlmer <- lmer(WingLength ~  Island*fYear + Sex + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IWLlmer)

#predicting the model
IWLlmerdata <- ggpredict(IWLlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,WingLength=predicted,Island=group,Sex=facet)
IWLlmerdata2 <- merge(IWLlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 25)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11)) %>% mutate(BirthYear = fYear + founderyear) %>% group_by(Island,BirthYear)%>% summarise(WingLength = mean(WingLength, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model
IWLmod <- ggplot(IWLlmerdata2, aes(x = BirthYear, y = WingLength, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=WingLength,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=WingLength-WLsd,ymax=WingLength+WLsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "lm", se = FALSE) + 
  geom_ribbon(aes(ymin=WingLength-std.error,ymax=WingLength+std.error),alpha=0.5) +
  labs(x = "Birth Year", y= "Wing Length (mm)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Head + Bill Length

#### Head + Bill ----
IHBlmer <- lmer(HeadBill ~  Island*fYear + Sex  + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IHBlmer)

#predicting the model
IHBlmerdata <- ggpredict(IHBlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,HeadBill=predicted,Island=group,SexEstimate=facet)
IHBlmerdata2 <- merge(IHBlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 22)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11))%>% mutate(BirthYear = fYear + founderyear)%>% group_by(Island,BirthYear)%>% summarise(HeadBill = mean(HeadBill, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model
IHBmod <- ggplot(IHBlmerdata2, aes(x = BirthYear, y = HeadBill, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=HeadBill,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=HeadBill-HBsd,ymax=HeadBill+HBsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "lm", se = FALSE) + 
  geom_ribbon(aes(ymin=HeadBill-std.error,ymax=HeadBill+std.error),alpha=0.25) +
  labs(x = "Birth Year", y= "Head + Bill Length (mm)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Arrange and plot

Imods <- ggarrange(IRTmod,IBMmod,IWLmod,IHBmod, common.legend=TRUE, labels = c("A","B","C","D"))
Imods

Lifespan and Reproduction

Preparing data

# make a non-redundant data set for lifespan and reproduction
ADD_Real <- ADD_I %>% filter(Island == "CN") %>% group_by(BirdID) %>% mutate(across(c(RightTarsus,BodyMass,WingLength,HeadBill),mean, na.rm=TRUE)) %>% filter(!duplicated(BirdID)) %>% select(RightTarsus,BodyMass,WingLength,HeadBill,BirdID,SexEstimate,BirthYear,Lifespan,SurvStatus,ReproductiveOutput) %>% mutate(SexEstimate = as.factor(SexEstimate))
# filter for missing values
ADD_tidy <- ADD_Real %>% filter(!is.na(RightTarsus) & !is.na(BodyMass)  & !is.na(WingLength)  & !is.na(HeadBill) & !is.na(SexEstimate)  & !is.na(Lifespan) ) %>% mutate(BodyCondition = BodyMass/RightTarsus) %>% mutate(SexEstimate = as.factor(SexEstimate))

Survival analysis with coxme

Model comparisons

###Lifespan analysis with coxme----

lscox0 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus+ BodyMass + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox1 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus+ poly(BodyMass,2) + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox2 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus*poly(BodyMass,2) + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox3 <- coxme(Surv(Lifespan,SurvStatus) ~ poly(BodyCondition,2) + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox4 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus+ poly(BodyMass,2)*SexEstimate + WingLength + HeadBill + (1|BirthYear), data= ADD_tidy)

AIC(lscox0,lscox1,lscox2,lscox3,lscox4) # lscox4 best
BIC(lscox0,lscox1,lscox2,lscox3,lscox4) # lscox4 best
# lscox4 was selected based on the best AIC and BIC values

lscox4

Predicting and plotting coxme

####predict lifespan----
ADD_round <- ADD_Real %>%mutate(across(c(RightTarsus, BodyMass, HeadBill, WingLength), round, 0)) %>% distinct(RightTarsus, BodyMass, HeadBill, WingLength,SexEstimate) %>% filter(!is.na(RightTarsus) & !is.na(BodyMass)  & !is.na(WingLength)  & !is.na(HeadBill) & !is.na(SexEstimate))
ADD_end <- bind_rows(ADD_tidy,ADD_round)
rs <- predict_coxme(lscox4,newdata = ADD_end,type="risk", se.fit=TRUE)
rsend <- ADD_end %>% add_columns(rr = rs$fit[,1], se.fit = rs$se.fit[,1])
ADD_tail <- rsend %>% tail(nrow(ADD_round)) %>% mutate(SexEstimate = as.factor(SexEstimate)) %>% group_by(BodyMass,SexEstimate) %>% summarise(mean_rr=mean(rr),mean_se.fit=mean(se.fit))

# plotting coxme
coxmeplot <- ggplot(ADD_tail,aes(x=BodyMass,y=mean_rr)) + 
  geom_line(aes(colour=SexEstimate)) +
  geom_ribbon(aes(fill=SexEstimate,ymin=mean_rr-mean_se.fit,ymax=mean_rr+mean_se.fit), alpha = 0.25) + 
  labs(x = "Body Mass (g)", y = "Mortality Risk Score") +
  guides(fill=guide_legend(title="Sex"), colour=guide_legend(title="Sex")) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind(labels = c("Female", "Male")) +
  scale_fill_colorblind(labels = c("Female", "Male"))

Reproductive Output using GLM

Model comparisons

###Reproduction glm----
ROglmF <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength + HeadBill  ,data = ADD_tidy, family = "poisson")
ROglmR <- glm(ReproductiveOutput ~ poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm0 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength + HeadBill  + Lifespan + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm1 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength  + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm2 <- glm(ReproductiveOutput ~ poly(RightTarsus,2)+ BodyMass + WingLength + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm3 <- glm(ReproductiveOutput ~ RightTarsus+ poly(BodyMass,2) + WingLength + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm4 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + poly(WingLength,2) + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm5 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength + poly(HeadBill,2)  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")

AIC(ROglmF,ROglmR,ROglm0,ROglm1,ROglm2,ROglm3,ROglm4,ROglm5) # ROglm4 slightly better than ROglm1 second
BIC(ROglmF,ROglmR,ROglm0,ROglm1,ROglm2,ROglm3,ROglm4,ROglm5) # ROglm1 best 
#ROglm1 was selected based on AIC and BIC scores
vif(ROglm1)

summary(ROglm1)

Predicting and plotting GLM

####predict reproduction----
# grouping variables for glm plot
ROplotdata <- ADD_tidy %>% mutate(BodyMass = case_when(BodyMass > 16.5 ~ "16.5", BodyMass < 14.5 ~ "14.5",BodyMass < 16.5 & BodyMass > 14.5 ~ "15.5")) %>% filter(!is.na(BodyMass))

# predicting glm 
ROglmdat <- ggpredict(ROglm1, terms = c("Lifespan","BodyMass")) %>% rename(Lifespan=x,ReproductiveOutput=predicted,BodyMass=group)

#plotting glm
ROglmplot <- ggplot(ROglmdat, aes(x=Lifespan,y=ReproductiveOutput)) + 
  geom_point(data = ROplotdata, mapping=aes(x=Lifespan,y=ReproductiveOutput,colour=BodyMass),position="jitter") +
  geom_smooth(aes(colour=BodyMass), se = FALSE) + 
  geom_ribbon(aes(ymin=conf.low,ymax=conf.high,fill=BodyMass), alpha = 0.25) +
  labs(x = "Lifespan (years)", y= "Total Number of Offspring") +
  theme_tufte(base_size = 15, base_family = "Arial") +
  scale_color_colorblind() + scale_fill_colorblind()

Arrange and plot

fitplot <- ggarrange(coxmeplot,ROglmplot,  labels = c("A","B"))
fitplot

Time taken to run the whole script

Acknowledgment

Thank you for going through the code and supporting open research. This paper would not have been possible without all authors contributing towards it. Massive thanks to everyone that has shared their excitement for this paper.

LS0tCnRpdGxlOiAnTW9ycGhvbG9naWNhbCBkaXZlcmdlbmNlIGluIGZyYWdtZW50ZWQgcG9wdWxhdGlvbnM6IE5vIGV2aWRlbmNlIG9mIGZpdG5lc3MKICBiZW5lZml0JwphdXRob3I6ICJDaHVlbiBaLiBMZWUsIFRob21hcyBKLiBCcm93biwgRGF2aWQgUy4gUmljaGFyZHNvbiIKZGF0ZTogIjIwMjMtMDYtMDEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogVFJVRQogICAgdGhlbWU6IHVuaXRlZAotLS0KClJhdyBjb2RlIGF2YWlsYWJsZSBhdCBbU1dfTW9ycGhvbG9neV0oaHR0cHM6Ly9naXRodWIuY29tL0NodWVuLUxlZS9TV19Nb3JwaG9sb2d5KQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSxvdXQud2lkdGggPSAnMTAwJScsICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPTEwLCBlcnJvciA9IFRSVUUpCmBgYAoKIyMgU3R1ZHkgRGVzaWduCgohW10oSW1hZ2VzL1N0dWR5RGVzaWduLnBuZykKCiMgU2V0dXAKCiMjIExvYWQgYWxsIHBhY2thZ2VzCgpgYGB7ciBsaWJyYXJpZXMsIGVjaG8gPSBULCBtZXNzYWdlID0gRkFMU0V9CiMgbGlicmFyaWVzCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KGNveG1lKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGVoYWhlbHBlcikKbGlicmFyeShnZ2VmZmVjdHMpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShyZWFkcikKbGlicmFyeShzam1pc2MpCmxpYnJhcnkoc3Vydml2YWwpCmBgYAoKIyMjIHNlc3Npb25JbmZvKCkKCjxkZXRhaWxzPgoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgo8L2RldGFpbHM+CgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpzdGFydF90aW1lPC1TeXMudGltZSgpCmBgYAoKIyMgRGF0YSBmaWxlcwoKRGF0YSBmaWxlIFtBRERfSV0oaHR0cHM6Ly9naXRodWIuY29tL0NodWVuLUxlZS9DaHVlbi1MZWUuZ2l0aHViLmlvL2Jsb2IvZjQ5NjhhMDAxZDM0YzUyMmE5MTJiYTNhMzUwYmIwNThkNTBhNDc3NS9wYWdlcy8yMDIzL1NleWNoZWxsZXNXYXJibGVyL1RhYmxlcy9BRERfSS5jc3YpIGlzIGF2YWlsYWJsZSBvbiB0aGUgZ2l0aHViIHBhZ2UuCgojIE1vcnBob21ldHJpYyBhbmQgSXNsYW5kIENvbXBhcmlzb24KCiMjIFByZXBhcmluZyBEYXRhCgpgYGB7ciBEYXRhIHRhYmxlcyBmb3IgaXNsYW5kfQojIHJlYWQgdGhlIGRhdGEgZmlsZSAiQUREX0kiCkFERF9JIDwtIHJlYWRfY3N2KCJUYWJsZXMvQUREX0kuY3N2IiwgY29sX3R5cGVzID0gY29scyhJc2xhbmQgPSBjb2xfZmFjdG9yKGxldmVscyA9IGMoIkNOIiwiQVIiLCAiQ0UiLCAiRFMiLCAiRlIiKSkpKQojIGNyZWF0ZSB0aGUgZWFybGllc3QgYm9ybiBpbmRpdmlkdWFscyBvbiBlYWNoIGlzbGFuZApJc2Z5IDwtIEFERF9JICU+JSBzZWxlY3QoZm91bmRlcnllYXIsSXNsYW5kKSAlPiUgZmlsdGVyKCFkdXBsaWNhdGVkKElzbGFuZCkpCiMgY3JlYXRlIGEgZGF0YSBmcmFtZSB3aXRoIG1lYW5zIGFuZCBzZCBvZiBlYWNoIG1vcnBob21ldHJpYwpBRERfbWVhbiA8LSBBRERfSSAlPiUgZ3JvdXBfYnkoSXNsYW5kLEJpcnRoWWVhcikgJT4lIHN1bW1hcmlzZShSVHNkID0gc2QoUmlnaHRUYXJzdXMsbmEucm09VFJVRSksV0xzZCA9IHNkKFdpbmdMZW5ndGgsbmEucm09VFJVRSksQk1zZCA9IHNkKEJvZHlNYXNzLG5hLnJtPVRSVUUpLEhCc2Q9c2QoSGVhZEJpbGwsbmEucm09VFJVRSksUmlnaHRUYXJzdXM9bWVhbihSaWdodFRhcnN1cyxuYS5ybT1UUlVFKSxXaW5nTGVuZ3RoPW1lYW4oV2luZ0xlbmd0aCxuYS5ybT1UUlVFKSxCb2R5TWFzcz1tZWFuKEJvZHlNYXNzLG5hLnJtPVRSVUUpLEhlYWRCaWxsPW1lYW4oSGVhZEJpbGwsbmEucm09VFJVRSkpCmBgYAoKIyMgTGluZWFyIE1peGVkIEVmZmVjdCBNb2RlbHMKCiMjIyBUYXJzdXMgTGVuZ3RoCgpgYGB7ciBydCwgbWVzc2FnZT1GQUxTRX0KIyMjI1JpZ2h0VGFyc3VzIC0tLS0KSVJUbG1lciA8LSBsbWVyKFJpZ2h0VGFyc3VzIH4gIElzbGFuZCpmWWVhciArIFNleCArICgxfE9ic2VydmVyKSArICgxfEFnZWNsYXNzKSArICgxfEJpcmRJRCksIGRhdGEgPSBBRERfSSkKc3VtbWFyeShJUlRsbWVyKQoKI3ByZWRpY3RpbmcgdGhlIG1vZGVsIApJUlRsbWVyZGF0YSA8LSBnZ3ByZWRpY3QoSVJUbG1lcix0ZXJtcz1jKCJmWWVhciBbYWxsXSIsIklzbGFuZCIsIlNleCIpKSAlPiUgcmVuYW1lKGZZZWFyPXgsUmlnaHRUYXJzdXM9cHJlZGljdGVkLElzbGFuZD1ncm91cCxTZXg9ZmFjZXQpCklSVGxtZXJkYXRhMiA8LSBtZXJnZShJUlRsbWVyZGF0YSxJc2Z5LGJ5PSJJc2xhbmQiLCBhbGwueD1UUlVFKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkFSIiAmIGZZZWFyID4gMjUpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkNFIiAmIGZZZWFyID4gMjUpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkRTIiAmIGZZZWFyID4gMTgpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkZSIiAmIGZZZWFyID4gMTEpKSU+JSBtdXRhdGUoQmlydGhZZWFyID0gZlllYXIgKyBmb3VuZGVyeWVhcikgJT4lIGdyb3VwX2J5KElzbGFuZCxCaXJ0aFllYXIpICU+JSBzdW1tYXJpc2UoUmlnaHRUYXJzdXMgPSBtZWFuKFJpZ2h0VGFyc3VzLCBuYS5ybT1UUlVFKSwgc3RkLmVycm9yID0gbWVhbihzdGQuZXJyb3IsIG5hLnJtPVRSVUUpKQoKI3Bsb3R0aW5nIHRoZSBtb2RlbCAoc2hvd24gYXMgZ2dhcnJhbmdlIGJlbG93KQpJUlRtb2QgPC0gZ2dwbG90KElSVGxtZXJkYXRhMiwgYWVzKHggPSBCaXJ0aFllYXIsIHkgPSBSaWdodFRhcnN1cywgZmlsbCA9IElzbGFuZCkpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gQUREX21lYW4sIG1hcHBpbmc9YWVzKHg9QmlydGhZZWFyLHk9UmlnaHRUYXJzdXMsY29sb3VyPUlzbGFuZCksIHNpemUgPSAyKSArCiAgZ2VvbV9lcnJvcmJhcihkYXRhPUFERF9tZWFuLGFlcyh5bWluPVJpZ2h0VGFyc3VzLVJUc2QseW1heD1SaWdodFRhcnN1cytSVHNkLCBjb2xvdXI9SXNsYW5kKSxhbHBoYT0wLjcpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3VyID0gSXNsYW5kKSxtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArIAogIGdlb21fcmliYm9uKGFlcyh5bWluPVJpZ2h0VGFyc3VzLXN0ZC5lcnJvcix5bWF4PVJpZ2h0VGFyc3VzK3N0ZC5lcnJvciksYWxwaGE9MC41KSArCiAgbGFicyh4ID0gIkJpcnRoIFllYXIiLCB5PSAiVGFyc3VzIExlbmd0aCAobW0pIikgKwogIHhsaW0oMTk5MCwyMDIyKSArCiAgdGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTUsIGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKyAKICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKCkgKyBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKQpgYGAKCiMjIyBCb2R5IE1hc3MKCmBgYHtyIGJtLCBtZXNzYWdlPUZBTFNFfQojIyMjIEJvZHkgTWFzcyAtLS0tCklCTWxtZXIgPC0gbG1lcihCb2R5TWFzcyB+ICBJc2xhbmQqZlllYXIgKyBTZXggICsgKDF8T2JzZXJ2ZXIpICsgKDF8QWdlY2xhc3MpICsgKDF8QmlyZElEKSwgZGF0YSA9IEFERF9JKQpzdW1tYXJ5KElCTWxtZXIpCgojcHJlZGljdGluZyB0aGUgbW9kZWwKSUJNbG1lcmRhdGEgPC0gZ2dwcmVkaWN0KElCTWxtZXIsdGVybXM9YygiZlllYXIgW2FsbF0iLCJJc2xhbmQiLCJTZXgiKSkgJT4lIHJlbmFtZShmWWVhcj14LEJvZHlNYXNzPXByZWRpY3RlZCxJc2xhbmQ9Z3JvdXAsU2V4PWZhY2V0KQpJQk1sbWVyZGF0YTIgPC0gbWVyZ2UoSUJNbG1lcmRhdGEsSXNmeSxieT0iSXNsYW5kIiwgYWxsLng9VFJVRSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJBUiIgJiBmWWVhciA+IDI1KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJDRSIgJiBmWWVhciA+IDI1KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJEUyIgJiBmWWVhciA+IDE4KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJGUiIgJiBmWWVhciA+IDExKSklPiUgbXV0YXRlKEJpcnRoWWVhciA9IGZZZWFyICsgZm91bmRlcnllYXIpICAlPiUgZ3JvdXBfYnkoSXNsYW5kLEJpcnRoWWVhcikgJT4lIHN1bW1hcmlzZShCb2R5TWFzcyA9IG1lYW4oQm9keU1hc3MsIG5hLnJtPVRSVUUpLCBzdGQuZXJyb3IgPSBtZWFuKHN0ZC5lcnJvciwgbmEucm09VFJVRSkpCgojcGxvdHRpbmcgdGhlIG1vZGVsCklCTW1vZCA8LSBnZ3Bsb3QoSUJNbG1lcmRhdGEyLCBhZXMoeCA9IEJpcnRoWWVhciwgeSA9IEJvZHlNYXNzLCBmaWxsID0gSXNsYW5kKSkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBBRERfbWVhbiwgbWFwcGluZz1hZXMoeD1CaXJ0aFllYXIseT1Cb2R5TWFzcyxjb2xvdXI9SXNsYW5kKSwgc2l6ZSA9IDIpICsKICBnZW9tX2Vycm9yYmFyKGRhdGE9QUREX21lYW4sYWVzKHltaW49Qm9keU1hc3MtQk1zZCx5bWF4PUJvZHlNYXNzK0JNc2QsIGNvbG91cj1Jc2xhbmQpLGFscGhhPTAuNykgKwogIGdlb21fc21vb3RoKGFlcyhjb2xvdXIgPSBJc2xhbmQpLG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsgCiAgZ2VvbV9yaWJib24oYWVzKHltaW49Qm9keU1hc3Mtc3RkLmVycm9yLHltYXg9Qm9keU1hc3Mrc3RkLmVycm9yKSxhbHBoYT0wLjUpICsKICBsYWJzKHggPSAiQmlydGggWWVhciIsIHk9ICJCb2R5IE1hc3MgKGcpIikgKwogIHhsaW0oMTk5MCwyMDIyKSArCiAgdGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTUsIGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKyAKICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKCkgKyBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKQoKYGBgCgojIyMgV2luZyBMZW5ndGgKCmBgYHtyIHdsLCBtZXNzYWdlPUZBTFNFfQojIyMjIFdpbmcgTGVuZ3RoIC0tLS0KSVdMbG1lciA8LSBsbWVyKFdpbmdMZW5ndGggfiAgSXNsYW5kKmZZZWFyICsgU2V4ICsgKDF8T2JzZXJ2ZXIpICsgKDF8QWdlY2xhc3MpICsgKDF8QmlyZElEKSwgZGF0YSA9IEFERF9JKQpzdW1tYXJ5KElXTGxtZXIpCgojcHJlZGljdGluZyB0aGUgbW9kZWwKSVdMbG1lcmRhdGEgPC0gZ2dwcmVkaWN0KElXTGxtZXIsdGVybXM9YygiZlllYXIgW2FsbF0iLCJJc2xhbmQiLCJTZXgiKSkgJT4lIHJlbmFtZShmWWVhcj14LFdpbmdMZW5ndGg9cHJlZGljdGVkLElzbGFuZD1ncm91cCxTZXg9ZmFjZXQpCklXTGxtZXJkYXRhMiA8LSBtZXJnZShJV0xsbWVyZGF0YSxJc2Z5LGJ5PSJJc2xhbmQiLCBhbGwueD1UUlVFKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkFSIiAmIGZZZWFyID4gMjUpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkNFIiAmIGZZZWFyID4gMjUpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkRTIiAmIGZZZWFyID4gMTgpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkZSIiAmIGZZZWFyID4gMTEpKSAlPiUgbXV0YXRlKEJpcnRoWWVhciA9IGZZZWFyICsgZm91bmRlcnllYXIpICU+JSBncm91cF9ieShJc2xhbmQsQmlydGhZZWFyKSU+JSBzdW1tYXJpc2UoV2luZ0xlbmd0aCA9IG1lYW4oV2luZ0xlbmd0aCwgbmEucm09VFJVRSksIHN0ZC5lcnJvciA9IG1lYW4oc3RkLmVycm9yLCBuYS5ybT1UUlVFKSkKCiNwbG90dGluZyB0aGUgbW9kZWwKSVdMbW9kIDwtIGdncGxvdChJV0xsbWVyZGF0YTIsIGFlcyh4ID0gQmlydGhZZWFyLCB5ID0gV2luZ0xlbmd0aCwgZmlsbCA9IElzbGFuZCkpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gQUREX21lYW4sIG1hcHBpbmc9YWVzKHg9QmlydGhZZWFyLHk9V2luZ0xlbmd0aCxjb2xvdXI9SXNsYW5kKSwgc2l6ZSA9IDIpICsKICBnZW9tX2Vycm9yYmFyKGRhdGE9QUREX21lYW4sYWVzKHltaW49V2luZ0xlbmd0aC1XTHNkLHltYXg9V2luZ0xlbmd0aCtXTHNkLCBjb2xvdXI9SXNsYW5kKSxhbHBoYT0wLjcpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3VyID0gSXNsYW5kKSxtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArIAogIGdlb21fcmliYm9uKGFlcyh5bWluPVdpbmdMZW5ndGgtc3RkLmVycm9yLHltYXg9V2luZ0xlbmd0aCtzdGQuZXJyb3IpLGFscGhhPTAuNSkgKwogIGxhYnMoeCA9ICJCaXJ0aCBZZWFyIiwgeT0gIldpbmcgTGVuZ3RoIChtbSkiKSArCiAgeGxpbSgxOTkwLDIwMjIpICsKICB0aGVtZV90dWZ0ZShiYXNlX3NpemUgPSAxNSwgYmFzZV9mYW1pbHkgPSAiQXJpYWwiKSArIAogIHNjYWxlX2NvbG9yX2NvbG9yYmxpbmQoKSArIHNjYWxlX2ZpbGxfY29sb3JibGluZCgpCgpgYGAKCiMjIyBIZWFkICsgQmlsbCBMZW5ndGgKCmBgYHtyIGhiLCBtZXNzYWdlPUZBTFNFfQojIyMjIEhlYWQgKyBCaWxsIC0tLS0KSUhCbG1lciA8LSBsbWVyKEhlYWRCaWxsIH4gIElzbGFuZCpmWWVhciArIFNleCAgKyAoMXxPYnNlcnZlcikgKyAoMXxBZ2VjbGFzcykgKyAoMXxCaXJkSUQpLCBkYXRhID0gQUREX0kpCnN1bW1hcnkoSUhCbG1lcikKCiNwcmVkaWN0aW5nIHRoZSBtb2RlbApJSEJsbWVyZGF0YSA8LSBnZ3ByZWRpY3QoSUhCbG1lcix0ZXJtcz1jKCJmWWVhciBbYWxsXSIsIklzbGFuZCIsIlNleCIpKSAlPiUgcmVuYW1lKGZZZWFyPXgsSGVhZEJpbGw9cHJlZGljdGVkLElzbGFuZD1ncm91cCxTZXhFc3RpbWF0ZT1mYWNldCkKSUhCbG1lcmRhdGEyIDwtIG1lcmdlKElIQmxtZXJkYXRhLElzZnksYnk9IklzbGFuZCIsIGFsbC54PVRSVUUpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiQVIiICYgZlllYXIgPiAyMikpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiQ0UiICYgZlllYXIgPiAyNSkpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiRFMiICYgZlllYXIgPiAxOCkpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiRlIiICYgZlllYXIgPiAxMSkpJT4lIG11dGF0ZShCaXJ0aFllYXIgPSBmWWVhciArIGZvdW5kZXJ5ZWFyKSU+JSBncm91cF9ieShJc2xhbmQsQmlydGhZZWFyKSU+JSBzdW1tYXJpc2UoSGVhZEJpbGwgPSBtZWFuKEhlYWRCaWxsLCBuYS5ybT1UUlVFKSwgc3RkLmVycm9yID0gbWVhbihzdGQuZXJyb3IsIG5hLnJtPVRSVUUpKQoKI3Bsb3R0aW5nIHRoZSBtb2RlbApJSEJtb2QgPC0gZ2dwbG90KElIQmxtZXJkYXRhMiwgYWVzKHggPSBCaXJ0aFllYXIsIHkgPSBIZWFkQmlsbCwgZmlsbCA9IElzbGFuZCkpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gQUREX21lYW4sIG1hcHBpbmc9YWVzKHg9QmlydGhZZWFyLHk9SGVhZEJpbGwsY29sb3VyPUlzbGFuZCksIHNpemUgPSAyKSArCiAgZ2VvbV9lcnJvcmJhcihkYXRhPUFERF9tZWFuLGFlcyh5bWluPUhlYWRCaWxsLUhCc2QseW1heD1IZWFkQmlsbCtIQnNkLCBjb2xvdXI9SXNsYW5kKSxhbHBoYT0wLjcpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3VyID0gSXNsYW5kKSxtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArIAogIGdlb21fcmliYm9uKGFlcyh5bWluPUhlYWRCaWxsLXN0ZC5lcnJvcix5bWF4PUhlYWRCaWxsK3N0ZC5lcnJvciksYWxwaGE9MC4yNSkgKwogIGxhYnMoeCA9ICJCaXJ0aCBZZWFyIiwgeT0gIkhlYWQgKyBCaWxsIExlbmd0aCAobW0pIikgKwogIHhsaW0oMTk5MCwyMDIyKSArCiAgdGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTUsIGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKyAKICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKCkgKyBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKQpgYGAKCiMjIEFycmFuZ2UgYW5kIHBsb3QKCmBgYHtyIGlzbGFuZCBwbG90LCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMH0KSW1vZHMgPC0gZ2dhcnJhbmdlKElSVG1vZCxJQk1tb2QsSVdMbW9kLElIQm1vZCwgY29tbW9uLmxlZ2VuZD1UUlVFLCBsYWJlbHMgPSBjKCJBIiwiQiIsIkMiLCJEIikpCkltb2RzCmBgYAoKIyBMaWZlc3BhbiBhbmQgUmVwcm9kdWN0aW9uCgojIyBQcmVwYXJpbmcgZGF0YQoKYGBge3IgZml0IGRhdGF9CiMgbWFrZSBhIG5vbi1yZWR1bmRhbnQgZGF0YSBzZXQgZm9yIGxpZmVzcGFuIGFuZCByZXByb2R1Y3Rpb24KQUREX1JlYWwgPC0gQUREX0kgJT4lIGZpbHRlcihJc2xhbmQgPT0gIkNOIikgJT4lIGdyb3VwX2J5KEJpcmRJRCkgJT4lIG11dGF0ZShhY3Jvc3MoYyhSaWdodFRhcnN1cyxCb2R5TWFzcyxXaW5nTGVuZ3RoLEhlYWRCaWxsKSxtZWFuLCBuYS5ybT1UUlVFKSkgJT4lIGZpbHRlcighZHVwbGljYXRlZChCaXJkSUQpKSAlPiUgc2VsZWN0KFJpZ2h0VGFyc3VzLEJvZHlNYXNzLFdpbmdMZW5ndGgsSGVhZEJpbGwsQmlyZElELFNleEVzdGltYXRlLEJpcnRoWWVhcixMaWZlc3BhbixTdXJ2U3RhdHVzLFJlcHJvZHVjdGl2ZU91dHB1dCkgJT4lIG11dGF0ZShTZXhFc3RpbWF0ZSA9IGFzLmZhY3RvcihTZXhFc3RpbWF0ZSkpCiMgZmlsdGVyIGZvciBtaXNzaW5nIHZhbHVlcwpBRERfdGlkeSA8LSBBRERfUmVhbCAlPiUgZmlsdGVyKCFpcy5uYShSaWdodFRhcnN1cykgJiAhaXMubmEoQm9keU1hc3MpICAmICFpcy5uYShXaW5nTGVuZ3RoKSAgJiAhaXMubmEoSGVhZEJpbGwpICYgIWlzLm5hKFNleEVzdGltYXRlKSAgJiAhaXMubmEoTGlmZXNwYW4pICkgJT4lIG11dGF0ZShCb2R5Q29uZGl0aW9uID0gQm9keU1hc3MvUmlnaHRUYXJzdXMpICU+JSBtdXRhdGUoU2V4RXN0aW1hdGUgPSBhcy5mYWN0b3IoU2V4RXN0aW1hdGUpKQpgYGAKCiMjIFN1cnZpdmFsIGFuYWx5c2lzIHdpdGggY294bWUKCiMjIyBNb2RlbCBjb21wYXJpc29ucwoKYGBge3IgY294bWV9CiMjI0xpZmVzcGFuIGFuYWx5c2lzIHdpdGggY294bWUtLS0tCgpsc2NveDAgPC0gY294bWUoU3VydihMaWZlc3BhbixTdXJ2U3RhdHVzKSB+IFJpZ2h0VGFyc3VzKyBCb2R5TWFzcyArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCArU2V4RXN0aW1hdGUgKyAoMXxCaXJ0aFllYXIpLCBkYXRhPSBBRERfdGlkeSkKbHNjb3gxIDwtIGNveG1lKFN1cnYoTGlmZXNwYW4sU3VydlN0YXR1cykgfiBSaWdodFRhcnN1cysgcG9seShCb2R5TWFzcywyKSArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCArU2V4RXN0aW1hdGUgKyAoMXxCaXJ0aFllYXIpLCBkYXRhPSBBRERfdGlkeSkKbHNjb3gyIDwtIGNveG1lKFN1cnYoTGlmZXNwYW4sU3VydlN0YXR1cykgfiBSaWdodFRhcnN1cypwb2x5KEJvZHlNYXNzLDIpICsgV2luZ0xlbmd0aCArIEhlYWRCaWxsICtTZXhFc3RpbWF0ZSArICgxfEJpcnRoWWVhciksIGRhdGE9IEFERF90aWR5KQpsc2NveDMgPC0gY294bWUoU3VydihMaWZlc3BhbixTdXJ2U3RhdHVzKSB+IHBvbHkoQm9keUNvbmRpdGlvbiwyKSArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCArU2V4RXN0aW1hdGUgKyAoMXxCaXJ0aFllYXIpLCBkYXRhPSBBRERfdGlkeSkKbHNjb3g0IDwtIGNveG1lKFN1cnYoTGlmZXNwYW4sU3VydlN0YXR1cykgfiBSaWdodFRhcnN1cysgcG9seShCb2R5TWFzcywyKSpTZXhFc3RpbWF0ZSArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCArICgxfEJpcnRoWWVhciksIGRhdGE9IEFERF90aWR5KQoKQUlDKGxzY294MCxsc2NveDEsbHNjb3gyLGxzY294Myxsc2NveDQpICMgbHNjb3g0IGJlc3QKQklDKGxzY294MCxsc2NveDEsbHNjb3gyLGxzY294Myxsc2NveDQpICMgbHNjb3g0IGJlc3QKIyBsc2NveDQgd2FzIHNlbGVjdGVkIGJhc2VkIG9uIHRoZSBiZXN0IEFJQyBhbmQgQklDIHZhbHVlcwoKbHNjb3g0CmBgYAoKIyMjIFByZWRpY3RpbmcgYW5kIHBsb3R0aW5nIGNveG1lCgpgYGB7ciBjb3htZSBwcmVkaWN0fQojIyMjcHJlZGljdCBsaWZlc3Bhbi0tLS0KQUREX3JvdW5kIDwtIEFERF9SZWFsICU+JW11dGF0ZShhY3Jvc3MoYyhSaWdodFRhcnN1cywgQm9keU1hc3MsIEhlYWRCaWxsLCBXaW5nTGVuZ3RoKSwgcm91bmQsIDApKSAlPiUgZGlzdGluY3QoUmlnaHRUYXJzdXMsIEJvZHlNYXNzLCBIZWFkQmlsbCwgV2luZ0xlbmd0aCxTZXhFc3RpbWF0ZSkgJT4lIGZpbHRlcighaXMubmEoUmlnaHRUYXJzdXMpICYgIWlzLm5hKEJvZHlNYXNzKSAgJiAhaXMubmEoV2luZ0xlbmd0aCkgICYgIWlzLm5hKEhlYWRCaWxsKSAmICFpcy5uYShTZXhFc3RpbWF0ZSkpCkFERF9lbmQgPC0gYmluZF9yb3dzKEFERF90aWR5LEFERF9yb3VuZCkKcnMgPC0gcHJlZGljdF9jb3htZShsc2NveDQsbmV3ZGF0YSA9IEFERF9lbmQsdHlwZT0icmlzayIsIHNlLmZpdD1UUlVFKQpyc2VuZCA8LSBBRERfZW5kICU+JSBhZGRfY29sdW1ucyhyciA9IHJzJGZpdFssMV0sIHNlLmZpdCA9IHJzJHNlLmZpdFssMV0pCkFERF90YWlsIDwtIHJzZW5kICU+JSB0YWlsKG5yb3coQUREX3JvdW5kKSkgJT4lIG11dGF0ZShTZXhFc3RpbWF0ZSA9IGFzLmZhY3RvcihTZXhFc3RpbWF0ZSkpICU+JSBncm91cF9ieShCb2R5TWFzcyxTZXhFc3RpbWF0ZSkgJT4lIHN1bW1hcmlzZShtZWFuX3JyPW1lYW4ocnIpLG1lYW5fc2UuZml0PW1lYW4oc2UuZml0KSkKCiMgcGxvdHRpbmcgY294bWUKY294bWVwbG90IDwtIGdncGxvdChBRERfdGFpbCxhZXMoeD1Cb2R5TWFzcyx5PW1lYW5fcnIpKSArIAogIGdlb21fbGluZShhZXMoY29sb3VyPVNleEVzdGltYXRlKSkgKwogIGdlb21fcmliYm9uKGFlcyhmaWxsPVNleEVzdGltYXRlLHltaW49bWVhbl9yci1tZWFuX3NlLmZpdCx5bWF4PW1lYW5fcnIrbWVhbl9zZS5maXQpLCBhbHBoYSA9IDAuMjUpICsgCiAgbGFicyh4ID0gIkJvZHkgTWFzcyAoZykiLCB5ID0gIk1vcnRhbGl0eSBSaXNrIFNjb3JlIikgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iU2V4IiksIGNvbG91cj1ndWlkZV9sZWdlbmQodGl0bGU9IlNleCIpKSArCiAgdGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTUsIGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKyAKICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKGxhYmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpICsKICBzY2FsZV9maWxsX2NvbG9yYmxpbmQobGFiZWxzID0gYygiRmVtYWxlIiwgIk1hbGUiKSkKYGBgCgojIyBSZXByb2R1Y3RpdmUgT3V0cHV0IHVzaW5nIEdMTQoKIyMjIE1vZGVsIGNvbXBhcmlzb25zCgpgYGB7ciBnbG19CiMjI1JlcHJvZHVjdGlvbiBnbG0tLS0tClJPZ2xtRiA8LSBnbG0oUmVwcm9kdWN0aXZlT3V0cHV0IH4gUmlnaHRUYXJzdXMrIEJvZHlNYXNzICsgV2luZ0xlbmd0aCArIEhlYWRCaWxsICAsZGF0YSA9IEFERF90aWR5LCBmYW1pbHkgPSAicG9pc3NvbiIpClJPZ2xtUiA8LSBnbG0oUmVwcm9kdWN0aXZlT3V0cHV0IH4gcG9seShMaWZlc3BhbiwyKSArIFNleEVzdGltYXRlICsgQmlydGhZZWFyLGRhdGEgPSBBRERfdGlkeSwgZmFtaWx5ID0gInBvaXNzb24iKQpST2dsbTAgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IFJpZ2h0VGFyc3VzKyBCb2R5TWFzcyArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCAgKyBMaWZlc3BhbiArIFNleEVzdGltYXRlICsgQmlydGhZZWFyLGRhdGEgPSBBRERfdGlkeSwgZmFtaWx5ID0gInBvaXNzb24iKQpST2dsbTEgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IFJpZ2h0VGFyc3VzKyBCb2R5TWFzcyArIFdpbmdMZW5ndGggICsgSGVhZEJpbGwgICsgcG9seShMaWZlc3BhbiwyKSArIFNleEVzdGltYXRlICsgQmlydGhZZWFyLGRhdGEgPSBBRERfdGlkeSwgZmFtaWx5ID0gInBvaXNzb24iKQpST2dsbTIgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IHBvbHkoUmlnaHRUYXJzdXMsMikrIEJvZHlNYXNzICsgV2luZ0xlbmd0aCArIEhlYWRCaWxsICArIHBvbHkoTGlmZXNwYW4sMikgKyBTZXhFc3RpbWF0ZSArIEJpcnRoWWVhcixkYXRhID0gQUREX3RpZHksIGZhbWlseSA9ICJwb2lzc29uIikKUk9nbG0zIDwtIGdsbShSZXByb2R1Y3RpdmVPdXRwdXQgfiBSaWdodFRhcnN1cysgcG9seShCb2R5TWFzcywyKSArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCAgKyBwb2x5KExpZmVzcGFuLDIpICsgU2V4RXN0aW1hdGUgKyBCaXJ0aFllYXIsZGF0YSA9IEFERF90aWR5LCBmYW1pbHkgPSAicG9pc3NvbiIpClJPZ2xtNCA8LSBnbG0oUmVwcm9kdWN0aXZlT3V0cHV0IH4gUmlnaHRUYXJzdXMrIEJvZHlNYXNzICsgcG9seShXaW5nTGVuZ3RoLDIpICsgSGVhZEJpbGwgICsgcG9seShMaWZlc3BhbiwyKSArIFNleEVzdGltYXRlICsgQmlydGhZZWFyLGRhdGEgPSBBRERfdGlkeSwgZmFtaWx5ID0gInBvaXNzb24iKQpST2dsbTUgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IFJpZ2h0VGFyc3VzKyBCb2R5TWFzcyArIFdpbmdMZW5ndGggKyBwb2x5KEhlYWRCaWxsLDIpICArIHBvbHkoTGlmZXNwYW4sMikgKyBTZXhFc3RpbWF0ZSArIEJpcnRoWWVhcixkYXRhID0gQUREX3RpZHksIGZhbWlseSA9ICJwb2lzc29uIikKCkFJQyhST2dsbUYsUk9nbG1SLFJPZ2xtMCxST2dsbTEsUk9nbG0yLFJPZ2xtMyxST2dsbTQsUk9nbG01KSAjIFJPZ2xtNCBzbGlnaHRseSBiZXR0ZXIgdGhhbiBST2dsbTEgc2Vjb25kCkJJQyhST2dsbUYsUk9nbG1SLFJPZ2xtMCxST2dsbTEsUk9nbG0yLFJPZ2xtMyxST2dsbTQsUk9nbG01KSAjIFJPZ2xtMSBiZXN0IAojUk9nbG0xIHdhcyBzZWxlY3RlZCBiYXNlZCBvbiBBSUMgYW5kIEJJQyBzY29yZXMKdmlmKFJPZ2xtMSkKCnN1bW1hcnkoUk9nbG0xKQpgYGAKCiMjIyBQcmVkaWN0aW5nIGFuZCBwbG90dGluZyBHTE0KCmBgYHtyIGdsbSBwcmVkaWN0fQojIyMjcHJlZGljdCByZXByb2R1Y3Rpb24tLS0tCiMgZ3JvdXBpbmcgdmFyaWFibGVzIGZvciBnbG0gcGxvdApST3Bsb3RkYXRhIDwtIEFERF90aWR5ICU+JSBtdXRhdGUoQm9keU1hc3MgPSBjYXNlX3doZW4oQm9keU1hc3MgPiAxNi41IH4gIjE2LjUiLCBCb2R5TWFzcyA8IDE0LjUgfiAiMTQuNSIsQm9keU1hc3MgPCAxNi41ICYgQm9keU1hc3MgPiAxNC41IH4gIjE1LjUiKSkgJT4lIGZpbHRlcighaXMubmEoQm9keU1hc3MpKQoKIyBwcmVkaWN0aW5nIGdsbSAKUk9nbG1kYXQgPC0gZ2dwcmVkaWN0KFJPZ2xtMSwgdGVybXMgPSBjKCJMaWZlc3BhbiIsIkJvZHlNYXNzIikpICU+JSByZW5hbWUoTGlmZXNwYW49eCxSZXByb2R1Y3RpdmVPdXRwdXQ9cHJlZGljdGVkLEJvZHlNYXNzPWdyb3VwKQoKI3Bsb3R0aW5nIGdsbQpST2dsbXBsb3QgPC0gZ2dwbG90KFJPZ2xtZGF0LCBhZXMoeD1MaWZlc3Bhbix5PVJlcHJvZHVjdGl2ZU91dHB1dCkpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gUk9wbG90ZGF0YSwgbWFwcGluZz1hZXMoeD1MaWZlc3Bhbix5PVJlcHJvZHVjdGl2ZU91dHB1dCxjb2xvdXI9Qm9keU1hc3MpLHBvc2l0aW9uPSJqaXR0ZXIiKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91cj1Cb2R5TWFzcyksIHNlID0gRkFMU0UpICsgCiAgZ2VvbV9yaWJib24oYWVzKHltaW49Y29uZi5sb3cseW1heD1jb25mLmhpZ2gsZmlsbD1Cb2R5TWFzcyksIGFscGhhID0gMC4yNSkgKwogIGxhYnMoeCA9ICJMaWZlc3BhbiAoeWVhcnMpIiwgeT0gIlRvdGFsIE51bWJlciBvZiBPZmZzcHJpbmciKSArCiAgdGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTUsIGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKwogIHNjYWxlX2NvbG9yX2NvbG9yYmxpbmQoKSArIHNjYWxlX2ZpbGxfY29sb3JibGluZCgpCmBgYAoKIyMgQXJyYW5nZSBhbmQgcGxvdAoKYGBge3IgZml0cGxvdHMsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTEwfQpmaXRwbG90IDwtIGdnYXJyYW5nZShjb3htZXBsb3QsUk9nbG1wbG90LCAgbGFiZWxzID0gYygiQSIsIkIiKSkKZml0cGxvdApgYGAKClRpbWUgdGFrZW4gdG8gcnVuIHRoZSB3aG9sZSBzY3JpcHQKCmBgYHtyIHRpbWUsIGVjaG89RkFMU0V9CmVuZF90aW1lPC1TeXMudGltZSgpCgpyb3VuZCgoZW5kX3RpbWUgLSBzdGFydF90aW1lKSwgMykKYGBgCgojIEFja25vd2xlZGdtZW50CgpUaGFuayB5b3UgZm9yIGdvaW5nIHRocm91Z2ggdGhlIGNvZGUgYW5kIHN1cHBvcnRpbmcgb3BlbiByZXNlYXJjaC4gVGhpcyBwYXBlciB3b3VsZCBub3QgaGF2ZSBiZWVuIHBvc3NpYmxlIHdpdGhvdXQgYWxsIGF1dGhvcnMgY29udHJpYnV0aW5nIHRvd2FyZHMgaXQuIE1hc3NpdmUgdGhhbmtzIHRvIGV2ZXJ5b25lIHRoYXQgaGFzIHNoYXJlZCB0aGVpciBleGNpdGVtZW50IGZvciB0aGlzIHBhcGVyLgoKPHAgYWxpZ249ImNlbnRlciI+CiFbXShJbWFnZXMvY2h1ZW5sb2dvdHJhbnNwYXJlbnRoZC5wbmcpe3dpZHRoPSIzMCUifQo8L3A+Cg==